package org.xx.armory.commons;

import java.util.Objects;

import static org.xx.armory.commons.Validators.rejectIfNegative;
import static org.xx.armory.commons.Validators.rejectIfNull;

/**
 * 数据相关的工具方法。
 */
public final class ArrayUtils {
    private ArrayUtils() {
        throw new AssertionError();
    }

    /**
     * 判断指定的对象是否是数组。
     *
     * @param o
     *         待判断的对象。
     * @return 是否是数组。
     */
    public static boolean isArray(
            Object o
    ) {
        return o instanceof Object[] || o instanceof char[] || o instanceof byte[] || o instanceof short[]
                || o instanceof int[] || o instanceof long[] || o instanceof float[] || o instanceof double[] || o instanceof boolean[];
    }

    /**
     * 截断数组到指定长度，如果源数组的长度比指定长度更短则使用空字符串填充。
     *
     * @param src
     *         源数组。
     * @param newLength
     *         指定长度。
     * @return 截断或者填充的结果。
     * @throws IllegalArgumentException
     *         如果参数 {@code src} 是 {@code null} 或者 {@code newLength} 小于 {@code 0}。
     */
    public static String[] truncate(
            String[] src,
            int newLength
    ) {
        rejectIfNull(src, "src");
        rejectIfNegative(newLength, "newLength");

        final var result = new String[newLength];

        final var n = Math.min(newLength, src.length);
        System.arraycopy(src, 0, result, 0, n);
        for (int i = n; i < newLength; ++i) {
            result[i] = "";
        }

        return result;
    }

    /**
     * 截断数组到指定长度，如果源数组的长度比指定长度更短则使用{@code null}填充。
     *
     * @param src
     *         源数组。
     * @param newLength
     *         指定长度。
     * @return 截断或者填充的结果。
     * @throws IllegalArgumentException
     *         如果参数 {@code src} 是 {@code null} 或者 {@code newLength} 小于 {@code 0}。
     */
    public static Object[] truncate(
            Object[] src,
            int newLength
    ) {
        rejectIfNull(src, "src");
        rejectIfNegative(newLength, "newLength");

        final var result = new Object[newLength];

        final var n = Math.min(newLength, src.length);
        System.arraycopy(src, 0, result, 0, n);
        for (int i = n; i < newLength; ++i) {
            result[i] = null;
        }

        return result;
    }

    /**
     * 截断数组到指定长度，如果源数组的长度比指定长度更短则使用{@code 0}填充。
     *
     * @param src
     *         源数组。
     * @param newLength
     *         指定长度。
     * @return 截断或者填充的结果。
     * @throws IllegalArgumentException
     *         如果参数 {@code src} 是 {@code null} 或者 {@code newLength} 小于 {@code 0}。
     */
    public static int[] truncate(
            int[] src,
            int newLength
    ) {
        rejectIfNull(src, "src");
        rejectIfNegative(newLength, "newLength");

        final var result = new int[newLength];

        final var n = Math.min(newLength, src.length);
        System.arraycopy(src, 0, result, 0, n);
        for (int i = n; i < newLength; ++i) {
            result[i] = 0;
        }

        return result;
    }

    /**
     * 截断数组到指定长度，如果源数组的长度比指定长度更短则使用{@code 0}填充。
     *
     * @param src
     *         源数组。
     * @param newLength
     *         指定长度。
     * @return 截断或者填充的结果。
     * @throws IllegalArgumentException
     *         如果参数 {@code src} 是 {@code null} 或者 {@code newLength} 小于 {@code 0}。
     */
    public static long[] truncate(
            long[] src,
            int newLength
    ) {
        rejectIfNull(src, "src");
        rejectIfNegative(newLength, "newLength");

        final var result = new long[newLength];

        final var n = Math.min(newLength, src.length);
        System.arraycopy(src, 0, result, 0, n);
        for (int i = n; i < newLength; ++i) {
            result[i] = 0L;
        }

        return result;
    }

    /**
     * 判断两个数组是否存在交集。
     *
     * @param a1
     *         数组1
     * @param a2
     *         数组2
     * @return 如果不存在交集则返回 {@code true}，否则返回 {@code false}。如果两个数组中任何一个是{@code null}也返回{@code true}。
     */
    public static boolean disjoint(
            int[] a1,
            int[] a2
    ) {
        if (a1 == null || a2 == null) return true;
        for (final var i : a1) {
            for (final var j : a2) {
                if (i == j)
                    return false;
            }
        }
        return true;
    }

    /**
     * 判断两个数组是否存在交集。
     *
     * @param a1
     *         数组1
     * @param a2
     *         数组2
     * @return 如果不存在交集则返回 {@code true}，否则返回 {@code false}。如果两个数组中任何一个是{@code null}也返回{@code true}。
     */
    public static boolean disjoint(
            Object[] a1,
            Object[] a2
    ) {
        if (a1 == null || a2 == null) return true;
        for (final var i : a1) {
            for (final var j : a2) {
                if (Objects.equals(i, j))
                    return false;
            }
        }
        return true;
    }
}
